package models

import (
	"encoding/json"
	"fmt"
	"github.com/XieWeikai/PlaceToGo/utils"
	"gorm.io/gorm"
	"time"
)

type ResponseStatus string

const (
	Pending           = "pending"           // 0: 待接受
	Agreed            = "agreed"            // 1: 同意
	Declined          = "declined"          // 2: 拒绝
	ResponseCancelled = "responseCancelled" // 3: 取消
)

type Response struct {
	gorm.Model
	RequestID   uint           `gorm:"not null" json:"requestId" binding:"required"` // 响应对应的请求
	UserID      uint           `gorm:"not null"`                                     // 响应者
	Description string         `json:"responseDescription" binding:"required"`
	ImageURL    string         `json:"responseImages"` // 假设响应介绍图片等文件通过URL链接提供
	Address     Address        `gorm:"embedded" json:"address" binding:"required"`
	Status      ResponseStatus `gorm:"not null"`
}

func (r *Response) MarshalJSON() ([]byte, error) {
	return json.Marshal(
		map[string]interface{}{
			"id":                  r.ID,
			"requestId":           r.RequestID,
			"responseDescription": r.Description,
			"responseImages":      r.ImageURL,
			"userId":              r.UserID,
			"status":              r.Status,
			"creationTime":        r.CreatedAt,
			"modificationTime":    r.UpdatedAt,
			"address":             r.Address,
		},
	)
}

type UpdateResponseDTO struct {
	Description string  `json:"responseDescription"`
	ImageURL    string  `json:"responseImages"`
	Address     Address `json:"address" gorm:"embedded"`
}

func (r *Response) CreateResponse() (*Response, error) {
	r.Status = Pending
	if e := DB.Create(r).Error; e != nil {
		return nil, e
	}
	return r, nil
}

func (r *Response) GetFirst(columns ...string) (*Response, error) {
	query := DB.Where(r)
	if len(columns) > 0 {
		query = query.Select(columns)
	}
	e := query.First(r).Error
	if e != nil {
		return nil, e
	}
	return r, nil
}

func (r *Response) GetResponses(limit int, offset int, sortBy string, sortOrder string, columns ...string) ([]Response, error) {
	var responses []Response
	query := DB.Where(r)

	if sortBy != "" {
		query = query.Order(sortBy + " " + sortOrder)
	}

	query = query.Limit(limit).Offset(offset)

	if len(columns) > 0 {
		query = query.Select(columns)
	}

	if err := query.Find(&responses).Error; err != nil {
		return nil, err
	}

	return responses, nil
}

func GetResponses(filter map[string]any, limit int, offset int, sortBy string, sortOrder string, columns ...string) ([]Response, int64, error) {
	var responses []Response
	query := DB.Model(&Response{})

	if q, ok := filter["q"]; ok {
		// 如果存在 q 参数，将其从 filter 中删除
		delete(filter, "q")

		// 将查询字符串转换为 GORM 查询
		qs, args := utils.SearchQuery(q.(string), "description", "status",
			"province", "city", "country")
		//log.Println("qs: ", qs, "args: ", args)
		query = query.Where(qs, args...)
	}

	query = query.Where(filter)

	if sortBy != "" {
		query = query.Order(sortBy + " " + sortOrder)
	}

	var cnt int64
	if err := query.Count(&cnt).Error; err != nil {
		return nil, 0, err
	}

	query = query.Limit(limit).Offset(offset)

	if len(columns) > 0 {
		query = query.Select(columns)
	}

	if err := query.Find(&responses).Error; err != nil {
		return nil, 0, err
	}

	return responses, cnt, nil
}

func (r *Response) UpdateById(u *UpdateResponseDTO) error {
	return DB.Model(r).Updates(u).Error
}

func (r *Response) Accept() error {
	// 开始事务
	tx := DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 更新当前Response的状态为Agreed
	if err := tx.Model(r).Update("Status", Agreed).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 找到并更新对应的Request的状态为Completed
	var request Request
	if err := tx.First(&request, r.RequestID).Error; err != nil {
		tx.Rollback()
		return err
	}
	if err := tx.Model(&request).Update("Status", Completed).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 更新其他Response的状态为Declined
	if err := tx.Model(&Response{}).Where("request_id = ? AND id != ? AND status = ?", r.RequestID, r.ID, Pending).Update("status", Declined).Error; err != nil {
		tx.Rollback()
		return err
	}

	var t TransactionDetail
	t.RequestID = r.RequestID
	t.PublisherID = request.UserID
	t.PublisherFee = 2.0
	t.ResponderID = r.UserID
	t.ResponderFee = 2.0
	t.CompletionDate = time.Now()

	if err := t.CreateTransaction(tx); err != nil {
		tx.Rollback()
		return err
	}

	if _, err := UpdateSummary(tx, t.CompletionDate, fmt.Sprintf("%s-%s", r.Address.Province, r.Address.City), request.PlaceType, 2.0+2.0); err != nil {
		tx.Rollback()
		return err
	}

	// 提交事务
	return tx.Commit().Error
}

func (r *Response) Cancel() error {
	return DB.Model(r).Update("status", ResponseCancelled).Error
}
